package com.dh.spring.client.file.upload;

import com.dh.spring.client.bootstrap.GlobalNIOClientBootstrap;
import com.dh.spring.client.bootstrap.FileCoreServiceHandler;
import com.dh.spring.client.file.common.SendEntity;
import com.dh.spring.client.bootstrap.ServerSocketChannelHttpRequestHandler;
import com.dh.spring.common.BasicConstant;
import com.dh.spring.util.LocalTime;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * 文件上传线程
 * */
@SuppressWarnings("all")
@Slf4j
public class SocketChannelUploadHandler implements Runnable {
    private FileChannel fileChannel;
    private String fileName;
    private int writedBytes = 0; //TODO 已上传字节数
    private SocketChannel socketChannel;
    private SelectionKey selectionKey;
    public volatile boolean flag = false; //TODO 当前通道数据是否可读
    private ByteBuffer byteBuffer = ByteBuffer.allocate(10 * 1024);// TODO SocketChannel实时读写缓冲区
    private int readEndEOF = -1; //TODO流读取文件末尾标志

    public SocketChannelUploadHandler(SelectionKey selectionKey, String fileName) {
        this.fileName = fileName;
        this.selectionKey = selectionKey;
        this.socketChannel = (SocketChannel) this.selectionKey.channel();
        this.fileChannel = GlobalNIOClientBootstrap.fileChannelsMap.get(this.selectionKey);
    }

    @Override
    public void run() {
        try {
            log.info("[" + LocalTime.formatDate(LocalDateTime.now()) + "] SocketChannelUploadHandler | --> fileName = {}, uploadPath = {}, 上传中请稍后...", this.fileName, ((SendEntity) this.selectionKey.attachment()).getPath());
            while (true) {
                if(!flag) {
                    TimeUnit.MILLISECONDS.sleep(50);
                    continue;
                }

                while ((this.readEndEOF = this.fileChannel.read(this.byteBuffer)) != -1) {
                    this.byteBuffer.flip(); //TODO 切换读模式
                    while(this.byteBuffer.hasRemaining()) {
                        this.writedBytes += this.socketChannel.write(this.byteBuffer);
                        /*log.info("[" + LocalTime.formatDate(LocalDateTime.now()) + "] SocketChannelUploadHandler | --> fileName = {}, 已上传字节数：writeBytes = {}", this.fileName, (this.writedBytes += this.socketChannel.write(this.byteBuffer)));*/
                    }
                    this.byteBuffer.clear();
                }

                if(this.readEndEOF == -1/* && ((long) writeFileLength) == filelength */) {
                    return;
                }

                flag = false;
            }
        } catch (Exception e) {
            log.error("[" + LocalTime.formatDate(LocalDateTime.now()) + "] SocketChannelUploadHandler | --> fileName = {}, 上传异常, exception = {}", this.fileName, e.getMessage());
        } finally {
            ServerSocketChannelHttpRequestHandler.fileExecStatusMap.get(BasicConstant.UPLOAD).remove(((SendEntity) this.selectionKey.attachment()).getFileExecStatus());
            log.info("[" + LocalTime.formatDate(LocalDateTime.now()) + "] FileCoreServiceHandler | --> 成功上传文件: fileName = {}, 并已从正在上传的文件队列中移除, 上传队列中剩余上传中的文件数: fileUploadCount = {}", this.fileName, ServerSocketChannelHttpRequestHandler.fileExecStatusMap.get(BasicConstant.UPLOAD).size());
            FileCoreServiceHandler.closeSocketChannel(this.selectionKey, this.fileChannel, "SocketChannelUploadHandler","", BasicConstant.UPLOAD, this.fileName, this.writedBytes);
        }
    }
}
